﻿// Doc-Encode UTF8-BOM, Space(4), Unix(LF)
#include "hiobj.h"
#include "hiobj_in.h"
#include "klbutil/klb_hash.h"
#include "klbmem/klb_mem.h"
#include "himpp_extension.h"
#include "klua/CKlua.hpp"
#include <assert.h>



hiobj_t* new_hiobj(lua_State* L, const char* p_name)
{
    himpp_extension_t* p_ex = himpp_ex_get_by_L(L);
    hiobj_reg_t* p_reg = himpp_ex_find(p_ex, p_name);

    int data_len = p_reg->size;
    int all_len = sizeof(hiobj_t) + data_len;

    hiobj_t* ptr = (hiobj_t*)lua_newuserdata(L, all_len);
    memset(ptr, 0, all_len);

    ptr->hash = klb_hash32(p_name, strlen(p_name));
    memcpy(&ptr->reg, p_reg, sizeof(hiobj_reg_t));

    // meta
    luaL_setmetatable(L, HIMPP_OBJ_HANDLE);

    return ptr;
}

hiobj_t* new_hiobj_mem(lua_State* L, int mem_idx, const char* p_name)
{
    himpp_extension_t* p_ex = himpp_ex_get_by_L(L);
    hiobj_reg_t* p_reg = himpp_ex_find(p_ex, p_name);
    klb_buf_t* p_tmp = himpp_ex_tmp_buf(p_ex, mem_idx);

    hiobj_t* ptr = (hiobj_t*)p_tmp->p_buf;
    assert(p_reg->size <= p_tmp->buf_len);
    KLB_MEMSET(ptr, 0, p_reg->size + sizeof(hiobj_t));

    ptr->hash = klb_hash32(p_name, strlen(p_name));
    memcpy(&ptr->reg, p_reg, sizeof(hiobj_reg_t));

    return ptr;
}

void hiobj_mem_set(hiobj_t* ptr, lua_State *L, int idx)
{
    assert(NULL != ptr);

    klb::CMap map;
    if (klb::CKlua::ParseToMap(L, idx, map))
    {
        if (ptr->reg.map2obj)
        {
            ptr->reg.map2obj(ptr, map);
        }
    }
}

void checktype_hiobj(lua_State* L, hiobj_t* ptr, const char* p_name)
{
    if (ptr->hash != klb_hash32(p_name, strlen(p_name)))
    {
        luaL_error(L, "hi obj:%s;need :%s", p_name, ptr->reg.p_name);
    }
}

hiobj_t* lua_checkhiobj(lua_State* L, int arg, int mem_idx, const char* p_name)
{
    hiobj_t* p_attr = NULL;

    if (lua_istable(L, arg))
    {
        p_attr = new_hiobj_mem(L, mem_idx, p_name);
        hiobj_mem_set(p_attr, L, arg);
    }
    else if (lua_isuserdata(L, arg))
    {
        p_attr = to_hiobj(L, arg);
        checktype_hiobj(L, p_attr, p_name);
    }
    else
    {
        luaL_error(L, "arg %d,need table or userdata hi obj", arg);
    }

    return p_attr;
}

void lua_pushhiobj_table(lua_State* L, hiobj_t* ptr)
{
    assert(NULL != ptr);
    assert(NULL != ptr->reg.obj2map);

    klb::CMap r;
    ptr->reg.obj2map(r, ptr);
    klb::CKlua::PushMapToLua(L, r);
}

static int hiobj_gc(lua_State* L)
{
    hiobj_t* p = to_hiobj(L, 1);

    return 0;
}

static int hiobj_tostring(lua_State* L)
{
    hiobj_t* p = to_hiobj(L, 1);

    lua_pushfstring(L, "hi obj:0x%p", p);
    return 1;
}

static int hiobj_Set(lua_State* L)
{
    hiobj_t* p = to_hiobj(L, 1); 
    hiobj_mem_set(p, L, 2);

    return 0;
}

static int hiobj_Get(lua_State* L)
{
    hiobj_t* p = to_hiobj(L, 1);

    klb::CMap map;
    if (p->reg.obj2map)
    {
        p->reg.obj2map(map, p);
    }

    klb::CKlua::PushMapToLua(L, map);
    return 1;
}

void createmeta_hiobj_handle(lua_State *L)
{
    static luaL_Reg reg[] = {
        { "__gc",               hiobj_gc },
        { "__tostring",         hiobj_tostring },

        { "Set",                hiobj_Set },
        { "Get",                hiobj_Get },

        { NULL,                 NULL }
    };

    luaL_newmetatable(L, HIMPP_OBJ_HANDLE);         /* create metatable for HIMPP_OBJ_HANDLE handles */
    lua_pushvalue(L, -1);                           /* push metatable */
    lua_setfield(L, -2, "__index");                 /* metatable.__index = metatable */
    luaL_setfuncs(L, reg, 0);                       /* add file methods to new metatable */
    lua_pop(L, 1);                                  /* pop new metatable */
}
